package com.ryder.petmatediarybackend.module.auth.task;

import com.ryder.petmatediarybackend.common.config.mq.RabbitMQConfig;
import com.ryder.petmatediarybackend.common.util.TaskLogUtil;
import com.ryder.petmatediarybackend.module.auth.message.BlacklistSyncMessage;
import com.ryder.petmatediarybackend.module.log.entity.SysTaskLog;
import com.ryder.petmatediarybackend.module.log.service.SysTaskLogService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * 描述: 认证数据同步定时任务（每10分钟扫描 Redis 黑名单 → 发送到 RabbitMQ）
 *
 * @author Ryder
 * @version 1.0
 * @since 1.0
 * 更新日期: 2025/10/28
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class BlacklistSyncTask {

    private final RedisTemplate<String, Object> redisTemplate;
    private final RabbitTemplate rabbitTemplate;
    private final SysTaskLogService taskLogService;

    /**
     * 每10分钟执行一次（扫描 Redis 中的黑名单数据并同步到 MySQL）
     */
    @Scheduled(cron = "0 */10 * * * ?")
    public void syncBlacklistToMQ() {
        TaskLogUtil.TaskLogBuilder builder = TaskLogUtil.start("AuthDataSyncTask");
        List<Long> blacklistIds = new ArrayList<>();

        try {
            log.info("========== 开始执行认证数据同步任务 ==========");

            // 1. 扫描 Redis 中的所有黑名单 Token
            // 黑名单 Key 格式：satoken:blacklist:{tokenValue}  111  SCAN 命令
            Set<String> blacklistKeys = redisTemplate.keys("satoken:blacklist:*");

            if (blacklistKeys == null || blacklistKeys.isEmpty()) {
                log.info("Redis 中没有黑名单数据，跳过同步");
                SysTaskLog taskLog = builder.totalCount(0).remark("无黑名单数据需要同步").finish();
                taskLogService.save(taskLog);
                return;
            }

            builder.totalCount(blacklistKeys.size());
            log.info("扫描到 {} 个黑名单 Token", blacklistKeys.size());

            // 2. 遍历黑名单，构建消息并发送到 MQ
            for (String blacklistKey : blacklistKeys) {
                try {
                    // 提取 tokenValue
                    String tokenValue = blacklistKey.replace("satoken:blacklist:", "");

                    // 获取 TTL（剩余过期时间）
                    Long ttl = redisTemplate.getExpire(blacklistKey, TimeUnit.SECONDS);
                    LocalDateTime expiredTime = null;
                    if (ttl != null && ttl > 0) {
                        expiredTime = LocalDateTime.now().plusSeconds(ttl);
                    }

                    // 构建消息
                    BlacklistSyncMessage message = BlacklistSyncMessage.builder()
                            .token(tokenValue)
                            .reason("用户注销")
                            .expiredTime(expiredTime)
                            .createTime(LocalDateTime.now())
                            .build();

                    // 发送到 RabbitMQ
                    rabbitTemplate.convertAndSend(RabbitMQConfig.BLACKLIST_SYNC_QUEUE, message);

                    // 记录成功
                    blacklistIds.add((long) tokenValue.hashCode());
                    builder.incrementSuccess();

                } catch (Exception e) {
                    log.error("处理黑名单 Token 失败：{}", blacklistKey, e);
                    builder.incrementFail();
                }
            }

            // 3. 保存任务日志
            SysTaskLog taskLog = builder
                    .blacklistIds(blacklistIds)
                    .remark(String.format("同步完成：黑名单 %d 条", blacklistKeys.size()))
                    .finish();
            taskLogService.save(taskLog);

            log.info("========== 认证数据同步任务执行完成：黑名单总数={}, 成功={}, 失败={} ==========",
                    taskLog.getTotalCount(), taskLog.getSuccessCount(), taskLog.getFailCount());

        } catch (Exception e) {
            log.error("认证数据同步任务执行失败", e);
            SysTaskLog taskLog = builder.fail(e);
            taskLogService.save(taskLog);
        }
    }
}
